﻿//========================================================= 
/**@file BluetoothCmdDriver.h
 * @brief 蓝牙设备名称驱动
 * 
 * @date 2016-10-31   21:58:09
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_BLUETOOTHCMDDRIVER_H_
#define _LIBZHOUYB_BLUETOOTHCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../../base_device/win32/BluetoothDevice.h"
using zhou_yb::base_device::env_win32::BluetoothDevice;

#include "../../../extension/ability/dev_helper/DevHelperForWin32.h"
using zhou_yb::extension::ability::BluetoothDeviceHelper;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// 蓝牙设备命令驱动
class BluetoothCmdDriver : public CommonCmdDriver
{
protected:
    Ref<IBaseDevice> _activeDev;
    Ref<IInteractiveTrans> _activeTrans;
    Ref<ITimeoutBehavior> _activeTimeout;
    BluetoothDevice _bthdev;
public:
    BluetoothCmdDriver() : CommonCmdDriver()
    {
        _activeDev = _bthdev;
        _activeTrans = _bthdev;
        _activeTimeout = _bthdev;

        _errGetter.Add(_bthdev);
        _logSetter.select(_bthdev);

        _RegisteCMD(BluetoothCmdDriver, EnumDevice);
        _RegisteCMD(BluetoothCmdDriver, ScanDevice);
        _RegisteCMD(BluetoothCmdDriver, EnumLocalDevice);

        _RegisteIBaseDeviceCMD(BluetoothCmdDriver);
        _RegisteIInteractiveTransCMD(BluetoothCmdDriver);
        _RegisteITimeoutCMD(BluetoothCmdDriver);
        _RegisteCancelCMD(BluetoothCmdDriver);

        _RegisteInterfaceCMD(BluetoothCmdDriver, IBaseDevice);
        _RegisteInterfaceCMD(BluetoothCmdDriver, IInteractiveTrans);
        _RegisteInterfaceCMD(BluetoothCmdDriver, ITimeoutBehavior);
    }
    /* Interface */
    LC_CMD_INTERFACE_GETTER(IBaseDevice, _activeDev);
    LC_CMD_INTERFACE_GETTER(IInteractiveTrans, _activeTrans);
    LC_CMD_INTERFACE_GETTER(ITimeoutBehavior, _activeTimeout);

    /**
     * @brief 扫描蓝牙设备
     * @date 2017-02-27 19:33
     * 
     * @param [in] Handle : pointer [default:NULL] 扫描时使用的本地蓝牙句柄,默认为自动选择本地蓝牙模块
     * @param [in] Timeout : uint [default:0] 扫描蓝牙的超时时间(ms)
     * @param [in] IsEnumAuthenticated : bool [default:true] 是否枚举认证过的设备(已配对)
     * @param [in] IsEnumRemembered : bool [default:true] 是否枚举记住的设备
     * @param [in] IsEnumUnknown : bool [default:true] 是否枚举未知设备
     * @param [in] IsEnumConnected : bool [default:true] 是否枚举已连接的设备
     * 
     * @retval Name : string 扫描到的蓝牙名称
     * @retval Handel : pointer 扫描到的蓝牙句柄
     * @retval Address : string 扫描到的蓝牙地址
     * @retval IsAuthenticated : bool 是否经过认证
     * @retval IsConnected : bool 是否已连接
     * @retval IsRemembered : bool 是否已保存
     * @retval Count : uint 扫描到的设备数目
     */
    LC_CMD_METHOD(ScanDevice)
    {
        list_t<BluetoothDevice::device_info> devlist;
        uint scanTimeoutMs = arg["Timeout"].To<uint>(0);
        HANDLE hLocalRadio = ctype_cast(HANDLE)(arg["Handle"].To<pointer>(NULL));

        BLUETOOTH_DEVICE_SEARCH_PARAMS  bdsp;
        ZeroMemory(&bdsp, sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
        bdsp.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
        bdsp.hRadio = NULL;
        bdsp.fReturnAuthenticated = ToBOOL(arg["IsEnumAuthenticated"].To<bool>(true));
        bdsp.fReturnRemembered = ToBOOL(arg["IsEnumRemembered"].To<bool>(true));
        bdsp.fReturnUnknown = ToBOOL(arg["IsEnumUnknown"].To<bool>(true));
        bdsp.fReturnConnected = ToBOOL(arg["IsEnumConnected"].To<bool>(true));
        bdsp.fIssueInquiry = ToBOOL(scanTimeoutMs > 0);
        bdsp.cTimeoutMultiplier = _itobyte(_max(scanTimeoutMs / 1000, 1));
        _bthdev.EnumRemoteDevice(devlist, hLocalRadio, &bdsp);

        list_t<BluetoothDevice::device_info>::iterator itr;
        for(itr = devlist.begin();itr != devlist.end(); ++itr)
        {
            rlt.Put("Name", itr->Name);
            rlt.Put("Handle", ArgConvert::ToString<pointer>(itr->hRadio));
            rlt.Put("Address", BluetoothDevice::AddressToString(itr->Address));
            rlt.Put("IsAuthenticated", ArgConvert::ToString(itr->IsAuthenticated));
            rlt.Put("IsConnected", ArgConvert::ToString(itr->IsConnected));
            rlt.Put("IsRemembered", ArgConvert::ToString(itr->IsRemembered));
        }
        rlt.Put("Count", ArgConvert::ToString(devlist.size()));
        return true;
    }
    /**
     * @brief 枚举当前的蓝牙设备
     * @date 2017-07-10 17:22
     * 
     * @retval Name : string 扫描到的蓝牙名称
     * @retval Address : string 扫描到的蓝牙地址
     * @retval LocalAddress : string 扫描设备的本地蓝牙地址
     * @retval IsAuthenticated : bool 是否经过认证
     * @retval IsConnected : bool 是否已连接
     * @retval Count : uint 扫描到的设备数目
     */
    LC_CMD_METHOD(EnumDevice)
    {
        list_t<BluetoothDevice::device_info> devlist;
        list_t<BTH_ADDR> adrlist;
        _bthdev.WsaEnumRemoteDevice(devlist, &adrlist);

        list_t<BluetoothDevice::device_info>::iterator itr;
        list_t<BTH_ADDR>::iterator adrItr;
        for(itr = devlist.begin(),adrItr = adrlist.begin();
            itr != devlist.end() && adrItr != adrlist.end(); 
            ++itr,++adrItr)
        {
            rlt.Put("Name", itr->Name);
            rlt.Put("Address", BluetoothDevice::AddressToString(itr->Address));
            rlt.Put("IsAuthenticated", ArgConvert::ToString(itr->IsAuthenticated));
            rlt.Put("IsConnected", ArgConvert::ToString(itr->IsConnected));
            rlt.Put("LocalAddress", BluetoothDevice::AddressToString(*adrItr));
        }
        rlt.Put("Count", ArgConvert::ToString(devlist.size()));
        return true;
    }
    /**
     * @brief 枚举本地设备
     * @date 2017-02-27 19:57
     * 
     * @retval Name : string 扫描到的蓝牙名称
     * @retval Address : string 扫描到的蓝牙地址
     * @retval Handle : pointer 本地蓝牙句柄
     * @retval Count : size_t 枚举到的本地蓝牙数目
     */
    LC_CMD_METHOD(EnumLocalDevice)
    {
        list_t<BluetoothDevice::device_info> devlist;
        _bthdev.EnumLocalDevice(devlist);

        list_t<BluetoothDevice::device_info>::iterator itr;
        for(itr = devlist.begin();itr != devlist.end(); ++itr)
        {
            rlt.Put("Name", itr->Name);
            rlt.Put("Address", BluetoothDevice::AddressToString(itr->Address));
            rlt.Put("Handle", ArgConvert::ToString<pointer>(itr->hRadio));
        }
        rlt.Put("Count", ArgConvert::ToString(devlist.size()));
        return true;
    }
    /**
     * @brief 打开蓝牙设备
     * @date 2016-09-28 23:02
     * 
     * @param [in] Timeout : uint [default:Null] 连接设备的超时时间(ms)
     * @param [in] Name : string 需要打开的蓝牙设备名称
     * @param [in] PIN : string [default:Null] 蓝牙配对的PIN码
     * @param [in] UUID : string [default:SerialPort] 蓝牙协议的UUID标识
     * @param [in] Port : uint [default:BT_PORT_ANY] 蓝牙端口[0,31]
     * @param [in] IsPairedOnly : bool [default:true] 是否只连接已配对的设备
     *
     * @retval Name : string 最后连接的设备完成名称
     */
    LC_CMD_METHOD(Open)
    {
        string sName = arg["Name"].To<string>();
        string sPin;
        const char* pPin = NULL;
        if(arg.Get("PIN", sPin) && sPin.length() > 0)
        {
            if(StringConvert::Compare(sPin.c_str(), "AUTO", true))
                sPin = "";
            pPin = sPin.c_str();
        }
        const char* pUuid = NULL;
        string sUuid;
        if(arg.Get("UUID", sUuid))
        {
            pUuid = sUuid.c_str();
        }
        uint port = arg["Port"].To<uint>(BT_PORT_ANY);
        string sTimeoutMs;
        uint timeoutMs = 0;
        bool isContainsTimeout = false;
        if(arg.Get("Timeout", sTimeoutMs))
        {
            timeoutMs = ArgConvert::FromString<uint>(sTimeoutMs);
            isContainsTimeout = true;
        }
        if(isContainsTimeout) timeoutMs = _bthdev.SetWaitTimeout(timeoutMs);
        bool isPairedOnly = arg["IsPairedOnly"].To<bool>(true);
        ByteBuilder fullName(8);
        DevHelper::ErrEnum err = BluetoothDeviceHelper::OpenDevice<BluetoothDevice>(
            _bthdev, sName.c_str(), pPin, pUuid, port, isPairedOnly, &fullName);
        if(isContainsTimeout) _bthdev.SetWaitTimeout(timeoutMs);
        switch(err)
        {
        case DevHelper::EnumERROR:
            _logErr(DeviceError::DevNotExistErr, "查找蓝牙失败");
            break;
        case DevHelper::EnumFAILE:
            _logErr(DeviceError::DevOpenErr);
            break;
        default:
            rlt.Put("Name", fullName.GetString());
            rlt.Put("Address", BluetoothDevice::AddressToString(_bthdev));
            break;
        }
        return DevHelper::IsHelperSuccess(err);
    }
    /**
     * @brief 打开指定地址的蓝牙设备
     * @date 2016-10-31 22:05
     * 
     * @param [in] Timeout : uint [default:Null] 连接设备的超时时间(ms)
     * @param [in] Address : string 蓝牙地址 XX:XX:XX 格式
     * @param [in] PIN : string [default:Null] 蓝牙配对的PIN码
     * @param [in] UUID : string [default:SerialPort] 蓝牙协议的UUID标识
     * @param [in] Port : [default:1] uint 蓝牙端口[0,31]
     */
    LC_CMD_METHOD(OpenWithAddress)
    {
        string sAdr = arg["Address"].To<string>();
        string sPin;
        const char* pPin = NULL;
        if(arg.Get("PIN", sPin))
        {
            pPin = sPin.c_str();
        }
        const char* pUuid = NULL;
        string sUuid;
        if(arg.Get("UUID", sUuid))
        {
            pUuid = sUuid.c_str();
        }
        uint port = arg["Port"].To<uint>(1);
        string sTimeoutMs;
        uint timeoutMs = 0;
        bool isContainsTimeout = false;
        if(arg.Get("Timeout", sTimeoutMs))
        {
            timeoutMs = ArgConvert::FromString<uint>(sTimeoutMs);
            isContainsTimeout = true;
        }
        if(isContainsTimeout) timeoutMs = _bthdev.SetWaitTimeout(timeoutMs);
        DevHelper::ErrEnum err = BluetoothDeviceHelper::OpenWithAddress<BluetoothDevice>(_bthdev, sAdr.c_str(), pPin, pUuid, port);
        if(isContainsTimeout) _bthdev.SetWaitTimeout(timeoutMs);
        switch(err)
        {
        case DevHelper::EnumERROR:
            _logErr(DeviceError::DevNotExistErr, "查找蓝牙失败");
            break;
        case DevHelper::EnumFAILE:
            _logErr(DeviceError::DevOpenErr);
            break;
        }
        return DevHelper::IsHelperSuccess(err);
    }
    /// 返回设备是否打开
    LC_CMD_METHOD(IsOpen)
    {
        ASSERT_FuncErr(_bthdev.IsOpen(), DeviceError::DevAlreadyCloseErr);
        return true;
    }
    /// 关闭设备
    LC_CMD_METHOD(Close)
    {
        _bthdev.Close();
        return true;
    }
    /**
     * @brief 删除配对
     * @date 2016-10-31 22:23
     * 
     * @param [in] Name : string [default:this] 需要删除配对的名称
     */
    LC_CMD_METHOD(RemovePair)
    {
        string sName;
        if(arg.Get("Name", sName))
        {
            BluetoothDevice::RemoveAll(sName.c_str());
        }
        else
        {
            BluetoothDevice::Remove(_bthdev);
        }
        return true;
    }

    LC_CMD_TIMEOUT(_bthdev);
    LC_CMD_CANCEL(_bthdev);
    LC_CMD_INTERACTIVETRANS(_bthdev);
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_BLUETOOTHCMDDRIVER_H_
//========================================================= 